package controller

import (
	"encoding/json"
	"fmt"
	"github.com/duke-git/lancet/v2/convertor"
	"github.com/gin-gonic/gin"
	"github.com/gorilla/websocket"
	"go.uber.org/zap"
	"kf/common"
	"kf/models/dao"
	"kf/models/entity"
	"kf/tools"
	"kf/utils/R"
	"kf/ws"
	"net/http"
	"os"
	"path"
	"strconv"
	"strings"
	"time"
)

type MessageController struct {
	SysUserDao      *dao.SysUserDao
	VisitorDao      *dao.VisitorsDao
	WsVisitor       *ws.WsVisitor
	WsUser          *ws.WsUser
	MessageDao      *dao.MessageDao
	ShoutController *ShoutController
	Log             *zap.Logger
}

type MessageForm struct {
	Content string `json:"content" form:"content"` //消息内容
	FromId  any    `json:"from_id" form:"from_id"` //来源方id
	ToId    string `json:"to_id" form:"to_id"`     //接收方id
	Type    string `json:"type" form:"type"`       //消息类型
}

// 发送单条消息
func (messageController *MessageController) SendMessageV2(c *gin.Context) {
	var form MessageForm
	err := c.ShouldBindJSON(&form)
	if err != nil {
		messageController.Log.Error("内容输入错误", zap.Error(err))
		c.JSON(200, gin.H{
			"code": 400,
			"msg":  "内容输入错误",
		})
		return
	}
	if form.Content == "" {
		c.JSON(200, gin.H{
			"code": 400,
			"msg":  "内容不能为空",
		})
		return
	}
	//限流
	if !tools.LimitFreqSingle("sendmessage:"+c.ClientIP(), 1, 2) {
		c.JSON(200, gin.H{
			"code": 400,
			"msg":  c.ClientIP() + "发送频率过快",
		})
		return
	}
	var kefuInfo entity.SysUser
	var visitorInfo entity.Visitor
	idAny := form.FromId
	id := convertor.ToString(idAny)
	if form.Type == "kefu" {
		toString := convertor.ToString(id)
		kefuInfo, err = messageController.SysUserDao.FindSysUserById(toString)
		if err != nil {
			messageController.Log.Error("查询客服错误", zap.Error(err))
			c.JSON(200, gin.H{
				"code": 400,
				"msg":  "查询客服错误",
			})
			return
		}
		visitorInfo = messageController.VisitorDao.FindVisitorByVisitorId(form.ToId)
	} else if form.Type == "visitor" {
		visitorInfo = messageController.VisitorDao.FindVisitorByVisitorId(id)
		kefuInfo, err = messageController.SysUserDao.FindSysUserById(form.ToId)
		if err != nil {
			messageController.Log.Error("查询客服错误", zap.Error(err))
			c.JSON(200, gin.H{
				"code": 400,
				"msg":  "查询客服错误",
			})
			return
		}
	}

	if kefuInfo.ID == 0 || visitorInfo.ID == 0 {
		c.JSON(200, gin.H{
			"code": 400,
			"msg":  "用户不存在",
		})
		return
	}
	//创建消息的同时，要给时间早于这条消息的聊天记录置为已读
	go messageController.MessageDao.CreateMessage(strconv.FormatUint(kefuInfo.ID, 10), visitorInfo.VisitorId, form.Content, form.Type)
	//不同的发送方式
	if form.Type == "kefu" {
		guest, ok := ws.ClientList[visitorInfo.VisitorId]
		if guest != nil && ok {
			//发送给客户
			messageController.WsVisitor.VisitorMessage(visitorInfo.VisitorId, form.Content, kefuInfo)
		}
		//发送给客服自己一份
		messageController.WsUser.KefuMessage(visitorInfo.VisitorId, form.Content, kefuInfo)
		c.JSON(200, gin.H{
			"code": 200,
			"msg":  "ok",
		})
	}
	if form.Type == "visitor" {
		guest, ok := ws.ClientList[visitorInfo.VisitorId]
		if ok && guest != nil {
			guest.UpdateTime = time.Now()
		}
		msg := ws.TypeMessage{
			Type: "message",
			Data: ws.ClientMessage{
				Avator:  visitorInfo.Avator,
				Id:      visitorInfo.VisitorId,
				Name:    visitorInfo.Name,
				ToId:    kefuInfo.UserName,
				Content: form.Content,
				Time:    time.Now().Format("2006-01-02 15:04:05"),
				IsKefu:  "no",
			},
		}
		str, _ := json.Marshal(msg)
		messageController.WsUser.OneKefuMessage(strconv.FormatUint(kefuInfo.ID, 10), str)
		//对客户的自动回复
		go messageController.WsVisitor.VisitorAutoReply(visitorInfo, kefuInfo, form.Content)
		c.JSON(200, gin.H{
			"code": 200,
			"msg":  "ok",
		})
	}
}

func (messageController *MessageController) SendVisitorNotice(c *gin.Context) {
	notice := c.Query("msg")
	if notice == "" {
		c.JSON(200, gin.H{
			"code": 400,
			"msg":  "msg不能为空",
		})
		return
	}
	msg := ws.TypeMessage{
		Type: "notice",
		Data: notice,
	}
	str, _ := json.Marshal(msg)
	for _, visitor := range ws.ClientList {
		err := visitor.Conn.WriteMessage(websocket.TextMessage, str)
		if err != nil {
			return
		}
	}
	c.JSON(200, gin.H{
		"code": 200,
		"msg":  "ok",
	})
}
func (messageController *MessageController) SendCloseMessageV2(c *gin.Context) {
	visitorId := c.Query("visitor_id")
	if visitorId == "" {
		c.JSON(200, gin.H{
			"code": 400,
			"msg":  "visitor_id不能为空",
		})
		return
	}

	oldUser, ok := ws.ClientList[visitorId]
	if oldUser != nil || ok {
		msg := ws.TypeMessage{
			Type: "force_close",
			Data: visitorId,
		}
		str, _ := json.Marshal(msg)
		err := oldUser.Conn.WriteMessage(websocket.TextMessage, str)
		oldUser.Conn.Close()
		delete(ws.ClientList, visitorId)
		messageController.Log.Info("close_message", zap.Any("user", oldUser), zap.Error(err))
	}
	c.JSON(200, gin.H{
		"code": 200,
		"msg":  "ok",
	})
}

// 上传图片
func UploadImg(c *gin.Context) {
	f, err := c.FormFile("imgfile")
	if err != nil {
		c.JSON(200, gin.H{
			"code": 400,
			"msg":  "上传失败!",
		})
		return
	} else {
		fileExt := strings.ToLower(path.Ext(f.Filename))
		if fileExt != ".png" && fileExt != ".jpg" && fileExt != ".gif" && fileExt != ".jpeg" {
			c.JSON(200, gin.H{
				"code": 400,
				"msg":  "上传失败!只允许png,jpg,gif,jpeg文件",
			})
			return
		}
		isMainUploadExist, _ := tools.IsFileExist(common.Upload)
		if !isMainUploadExist {
			os.Mkdir(common.Upload, os.ModePerm)
		}
		fileName := tools.Md5(fmt.Sprintf("%s%s", f.Filename, time.Now().String()))
		fileDir := fmt.Sprintf("%s%d%s/", common.Upload, time.Now().Year(), time.Now().Month().String())
		isExist, _ := tools.IsFileExist(fileDir)
		if !isExist {
			os.Mkdir(fileDir, os.ModePerm)
		}
		filepath := fmt.Sprintf("%s%s%s", fileDir, fileName, fileExt)
		c.SaveUploadedFile(f, filepath)
		c.JSON(200, gin.H{
			"code": 200,
			"msg":  "上传成功!",
			"data": gin.H{
				"path": filepath,
			},
		})
	}
}

// 上传文件
func UploadFile(c *gin.Context) {
	f, err := c.FormFile("file")
	if err != nil {
		c.JSON(200, gin.H{
			"code": 400,
			"msg":  "上传失败!",
		})
		return
	} else {
		fileExt := strings.ToLower(path.Ext(f.Filename))
		if f.Size >= 90*1024*1024 {
			c.JSON(200, gin.H{
				"code": 400,
				"msg":  "上传失败!不允许超过90M",
			})
			return
		}

		fileName := tools.Md5(fmt.Sprintf("%s%s", f.Filename, time.Now().String()))
		fildDir := fmt.Sprintf("%s%d%s/", common.Upload, time.Now().Year(), time.Now().Month().String())
		isExist, _ := tools.IsFileExist(fildDir)
		if !isExist {
			os.Mkdir(fildDir, os.ModePerm)
		}
		filepath := fmt.Sprintf("%s%s%s", fildDir, fileName, fileExt)
		c.SaveUploadedFile(f, filepath)
		c.JSON(200, gin.H{
			"code": 200,
			"msg":  "上传成功!",
			"data": gin.H{
				"path": filepath,
				"url":  filepath,
				"ext":  fileExt,
				"size": f.Size,
				"name": f.Filename,
			},
		})
	}
}
func (messageController *MessageController) GetMessagesV2(c *gin.Context) {
	visitorId := c.Query("visitor_id")
	messages := messageController.MessageDao.FindMessageByVisitorId(visitorId)
	//result := make([]map[string]interface{}, 0)
	chatMessages := make([]ChatMessage, 0)
	var visitor entity.Visitor
	var kefu entity.SysUser
	var err error
	for _, message := range messages {
		if visitor.Name == "" || kefu.UserName == "" {
			kefu, err = messageController.SysUserDao.FindSysUserById(message.KefuId)
			if err != nil {
				messageController.Log.Error("查询用户错误", zap.Error(err))
				break
			}
			visitor = messageController.VisitorDao.FindVisitorByVisitorId(message.VisitorId)
		}
		var chatMessage ChatMessage
		chatMessage.Time = message.CreatedAt.Format("2006-01-02 15:04:05")
		chatMessage.Content = message.Content
		chatMessage.MesType = message.MesType
		if message.MesType == "kefu" {
			chatMessage.Name = kefu.NickName
			chatMessage.Avator = kefu.Avatar
		} else {
			chatMessage.Name = visitor.Name
			chatMessage.Avator = visitor.Avator
		}
		chatMessages = append(chatMessages, chatMessage)
	}
	messageController.MessageDao.ReadMessageByVisitorId(visitorId)
	c.JSON(200, gin.H{
		"code":   200,
		"msg":    "ok",
		"result": chatMessages,
	})
}

// 分页查询历史消息
func (messageController *MessageController) GetMessagesPageByVisitor(c *gin.Context) {
	visitorId := c.Query("visitor_id")
	if visitorId == "" {
		c.JSON(http.StatusOK, R.ReturnFailMsg("缺少用户id"))
		return
	}
	page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
	pageSize, _ := strconv.Atoi(c.DefaultQuery("pagesize", "10"))
	if pageSize > 20 {
		pageSize = 20
	}
	count := messageController.MessageDao.CountMessage("visitor_id = ?", visitorId)
	list := messageController.MessageDao.FindMessageByPage(page, pageSize, "message.visitor_id = ?", visitorId)
	//将消息置为已读
	messageController.MessageDao.ReadMessageByVisitorId(visitorId)
	c.JSON(200, gin.H{
		"code": 200,
		"msg":  "ok",
		"data": gin.H{
			"count":    count,
			"page":     page,
			"list":     list,
			"pagesize": pageSize,
		},
	})
}

// 获取消息列表
func (messageController *MessageController) GetMessagesPage(context *gin.Context) {
	visitorId := context.Query("visitor_id")
	content := context.Query("content")
	page, _ := strconv.Atoi(context.DefaultQuery("pageNum", "1"))
	pageSize, _ := strconv.Atoi(context.DefaultQuery("pagesize", "10"))
	if pageSize > 20 {
		pageSize = 20
	}
	args := make([]any, 0)
	query := ""
	if visitorId != "" {
		query = " message.visitor_id = ? "
		args = append(args, visitorId)
	}
	if content != "" {
		if query != "" {
			query = query + " and "
		}
		query = query + " content like ?"
		args = append(args, "%"+content+"%")
	}
	count := messageController.MessageDao.CountMessage(query, args...)
	list := messageController.MessageDao.FindMessageByPage(page, pageSize, query, args...)
	context.JSON(200, gin.H{
		"code": 200,
		"msg":  "ok",
		"data": gin.H{
			"count":    count,
			"page":     page,
			"list":     list,
			"pagesize": pageSize,
		},
	})
}

// 客户的消息已读
func (messageController *MessageController) ReadMessage(context *gin.Context) {
	visitorId := context.Param("visitorId")
	messageController.MessageDao.ReadMessageByVisitorId(visitorId)
	context.JSON(http.StatusOK, R.ReturnSuccessMsg("ok"))
}
